home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / sticpsrc.lzh / SOURCE.ARC / EC.C < prev    next >
C/C++ Source or Header  |  1990-07-12  |  8KB  |  329 lines

  1. /* Driver for 3COM Ethernet card */
  2.  
  3. #define    TIMER    20000    /* Timeout on transmissions */
  4.  
  5. #include <stdio.h>
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "enet.h"
  9. #include "iface.h"
  10. #include "ec.h"
  11. #include "timer.h"
  12. #include "arp.h"
  13. #include "trace.h"
  14.  
  15. void ec0vec(),ec1vec(),ec2vec();
  16. void (*ecvec[])() = {ec0vec,ec1vec,ec2vec};
  17. struct ec ec[EC_MAX];        /* Per-controller info */
  18. unsigned nec = 0;
  19. extern int need_disable;
  20.  
  21. /* Initialize interface */
  22. int
  23. ec_init(interface,bufsize)
  24. struct interface *interface;
  25. unsigned bufsize;    /* Maximum size of receive queue in PACKETS */
  26. {
  27.     register struct ec *ecp;
  28.     register unsigned base;
  29.     void eaudit();
  30.     unsigned short getcs();
  31.     int16 dev;
  32.  
  33.     dev = interface->dev;
  34.     ecp = &ec[dev];
  35.     base = ecp->base;
  36.     ecp->rcvmax = bufsize;
  37.     ecp->iface = interface;
  38.  
  39.     /* Pulse IE_RESET */
  40.      outportb(IE_CSR(base),IE_RESET);
  41.  
  42.     /* Set interrupt vector */
  43.     if(setirq(ecp->vec,ecvec[dev]) == -1){
  44.         printf("IRQ %u out of range\n",ecp->vec);
  45.         return -1;
  46.     }
  47.     maskon(ecp->vec);    /* Enable interrupt */
  48.     if(interface->hwaddr == NULLCHAR)
  49.         interface->hwaddr = malloc(EADDR_LEN);
  50.     getecaddr(base,interface->hwaddr);
  51.     setecaddr(base,interface->hwaddr);
  52.     if(memcmp(interface->hwaddr,ether_bdcst,EADDR_LEN) == 0){
  53.         printf("EC address PROM contains broadcast address!!\n");
  54.         return -1;
  55.     }
  56.     /* Enable DMA/interrupt request, gain control of buffer */
  57.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  58.  
  59.     /* Enable transmit interrupts */
  60.     outportb(EDLC_XMT(base),EDLC_16 | EDLC_JAM);
  61.  
  62.     /* Set up the receiver interrupts and flush status */
  63.     outportb(EDLC_RCV(base),EDLC_MULTI|EDLC_GOOD|EDLC_ANY|EDLC_SHORT
  64.      |EDLC_DRIBBLE|EDLC_FCS|EDLC_OVER);
  65.     inportb(EDLC_RCV(base));
  66.  
  67.     /* Start receiver */
  68.     outportw(IE_RP(base),0);    /* Reset read pointer */
  69.     outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  70.     return 0;
  71. }
  72. /* Send raw packet (caller provides header) */
  73. int
  74. ec_raw(interface,bp)
  75. struct interface *interface;    /* Pointer to interface control block */
  76. struct mbuf *bp;        /* Data field */
  77. {
  78.     register struct ec *ecp;
  79.     register unsigned base;
  80.     register int i;
  81.     short size;
  82.  
  83.     ecp = &ec[interface->dev];
  84.     base = ecp->base;
  85.  
  86.     ecp->estats.xmit++;
  87.     dump(interface,IF_TRACE_OUT,TRACE_ETHER,bp);
  88.  
  89.     size = len_mbuf(bp);
  90.     /* Pad the size out to the minimum, if necessary,
  91.      * with junk from the last packet (nice security hole here)
  92.      */
  93.     if(size < RUNT)
  94.         size = RUNT;
  95.     size = (size+1) & ~1;    /* round size up to next even number */
  96.  
  97.     /* Wait for transmitter ready, if necessary. IE_XMTBSY is valid
  98.      * only in the transmit mode, hence the initial check.
  99.      */
  100.     if((inportb(IE_CSR(base)) & IE_BUFCTL) == IE_XMTEDLC){
  101.         for(i=TIMER;(inportb(IE_CSR(base)) & IE_XMTBSY) && i != 0;i--)
  102.             ;
  103.         if(i == 0){
  104.             ecp->estats.timeout++;
  105.             free_p(bp);
  106.             return -1;
  107.         }
  108.     }
  109.     ecp->size = size;
  110.     /* Get control of the board buffer and disable receiver */
  111.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  112.     /* Point GP at beginning of packet */
  113.     outportw(IE_GP(base),BFRSIZ-size);
  114.     /* Actually load each piece with a fast assembler routine */
  115.     while(bp != NULLBUF){
  116.         outbuf(IE_BFR(base),bp->data,bp->cnt);
  117.         bp = free_mbuf(bp);
  118.     }
  119.     /* Start transmitter */
  120.     outportw(IE_GP(base),BFRSIZ-size);
  121.     outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
  122.     return 0;
  123. }
  124. /* Ethernet interrupt handler */
  125. int
  126. ecint(dev)
  127. int dev;
  128. {
  129.     register struct ec *ecp;
  130.     register unsigned base;
  131.     struct mbuf *bp;
  132.     int16 size;
  133.     char stat;
  134.  
  135.     ecp = &ec[dev];
  136.     base = ec[dev].base;
  137.     ecp->estats.intrpt++;
  138.  
  139.     /* Check for transmit jam */
  140.     if(!(inportb(IE_CSR(base)) & IE_XMTBSY)){
  141.         stat = inportb(EDLC_XMT(base));
  142.         if(stat & EDLC_16){
  143.             ecp->estats.jam16++;
  144.             rcv_fixup(base);
  145.         } else if(stat & EDLC_JAM){
  146.             /* Crank counter back to beginning and restart transmit */
  147.             ecp->estats.jam++;
  148.             outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  149.             outportw(IE_GP(base),BFRSIZ - ecp->size);
  150.             outportb(IE_CSR(base),IE_RIDE|IE_XMTEDLC);
  151.         }
  152.     }
  153.     for(;;){
  154.         stat = inportb(EDLC_RCV(base));
  155.         if(stat & EDLC_STALE)
  156.             break;
  157.  
  158.         if(stat & EDLC_OVER){
  159.             ecp->estats.over++;
  160.             rcv_fixup(base);
  161.             continue;
  162.         }
  163.         if(stat & (EDLC_SHORT | EDLC_FCS | EDLC_DRIBBLE)){
  164.             ecp->estats.bad++;
  165.             rcv_fixup(base);
  166.             continue;
  167.         }
  168.         if(stat & EDLC_ANY){
  169.             /* Get control of the buffer */
  170.             outportw(IE_GP(base),0);
  171.             outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  172.         
  173.             /* Allocate mbuf and copy the packet into it */
  174.             size = inportw(IE_RP(base));
  175.             if(size < RUNT || size > GIANT)
  176.                 ecp->estats.bad++;
  177.             else if(ecp->rcvcnt >= ecp->rcvmax)
  178.                 ecp->estats.drop++;
  179.             else if((bp = alloc_mbuf(size)) == NULLBUF)
  180.                 ecp->estats.nomem++;
  181.             else {
  182.                 ecp->estats.recv++;
  183.                 inbuf(IE_BFR(base),bp->data,size);
  184.                 bp->cnt = size;
  185.                 ecp->rcvcnt++;
  186.                 enqueue(&ecp->rcvq,bp);/* Put it on the receive queue */
  187.             }
  188.             outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  189.             outportb(IE_RP(base),0);
  190.         }
  191.     }
  192.     /* Clear any spurious interrupts */
  193.     (void)inportb(EDLC_RCV(base));
  194.     (void)inportb(EDLC_XMT(base));
  195. }
  196. static
  197. rcv_fixup(base)
  198. register unsigned base;
  199. {
  200.     outportb(IE_CSR(base),IE_RIDE|IE_SYSBFR);
  201.     outportb(IE_CSR(base),IE_RIDE|IE_RCVEDLC);
  202.     outportb(IE_RP(base),0);
  203. }
  204. /* Process any incoming Ethernet packets on the receive queue */
  205. int
  206. ec_recv(interface)
  207. struct interface *interface;
  208. {
  209.     void arp_input();
  210.     int ip_route();
  211.     struct ec *ecp;
  212.     struct mbuf *bp;
  213.  
  214.     ecp = &ec[interface->dev];
  215.     if((bp = dequeue(&ecp->rcvq)) == NULLBUF)
  216.         return 0;
  217.  
  218.     ecp->rcvcnt--;
  219.     dump(interface,IF_TRACE_IN,TRACE_ETHER,bp);
  220.     eproc(interface,bp);
  221.  
  222.     return 1;
  223. }
  224. /* Read Ethernet address from controller PROM */
  225. static
  226. getecaddr(base,cp)
  227. register unsigned base;
  228. register char *cp;
  229. {
  230.     register int i;
  231.  
  232.     for(i=0;i<EADDR_LEN;i++){
  233.         outportw(IE_GP(base),i);
  234.         *cp++ = inportb(IE_SAPROM(base));
  235.     }
  236. }
  237. /* Set Ethernet address on controller */
  238. static
  239. setecaddr(base,cp)
  240. register unsigned base;
  241. register char *cp;
  242. {
  243.     register int i;
  244.  
  245.     for(i=0;i<EADDR_LEN;i++)
  246.         outportb(EDLC_ADDR(base)+i,*cp++);
  247. }
  248. /* Shut down the Ethernet controller */
  249. ec_stop(interface)
  250. struct interface *interface;
  251. {
  252.     register unsigned base;
  253.     int16 dev;
  254.  
  255.     dev = interface->dev;
  256.     base = ec[dev].base;
  257.  
  258.     /* Disable interrupt */
  259.     maskoff(ec[dev].vec);
  260.  
  261.     /* Pulse IE_RESET */
  262.     outportb(IE_CSR(base),IE_RESET);
  263.     outportb(IE_CSR(base),0);
  264. }
  265. /* Attach a 3-Com model 3C500 Ethernet controller to the system
  266.  * argv[0]: hardware type, must be "3c500"
  267.  * argv[1]: I/O address, e.g., "0x300"
  268.  * argv[2]: vector, e.g., "3"
  269.  * argv[3]: mode, must be "arpa"
  270.  * argv[4]: interface label, e.g., "ec0"
  271.  * argv[5]: maximum number of packets allowed on receive queue, e.g., "5"
  272.  * argv[6]: maximum transmission unit, bytes, e.g., "1500"
  273.  */
  274. ec_attach(argc,argv)
  275. int argc;
  276. char *argv[];
  277. {
  278.     register struct interface *if_ec;
  279.     extern struct interface *ifaces;
  280.     unsigned dev;
  281.     int ec_init();
  282.     int enet_send();
  283.     int enet_output();
  284.     int ec_stop();
  285.     int pether(),gaether();
  286.  
  287.     arp_init(ARP_ETHER,EADDR_LEN,IP_TYPE,ARP_TYPE,ether_bdcst,pether,gaether);
  288.     if(nec >= EC_MAX){
  289.         printf("Too many Ethernet controllers\n");
  290.         return -1;
  291.     }
  292.     dev = nec++;
  293.     if((if_ec = (struct interface *)calloc(1,sizeof(struct interface))) == NULLIF
  294.      ||(if_ec->name = malloc((unsigned)strlen(argv[4])+1)) == NULLCHAR){
  295.         printf("ec_attach: no memory!\n");
  296.         return -1;
  297.     }
  298.     strcpy(if_ec->name,argv[4]);
  299.     if_ec->mtu = atoi(argv[6]);
  300.     if_ec->send = enet_send;
  301.     if_ec->output = enet_output;
  302.     if_ec->raw = ec_raw;
  303.     if_ec->recv = ec_recv;
  304.     if_ec->stop = ec_stop;
  305.     if_ec->dev = dev;
  306.  
  307.     ec[dev].base = htoi(argv[1]);
  308.     ec[dev].vec = htoi(argv[2]);
  309.  
  310.     if(strcmp(argv[3],"arpa") != 0){
  311.         printf("Mode %s unknown for interface %s\n",
  312.             argv[3],argv[4]);
  313.         free(if_ec->name);
  314.         free((char *)if_ec);
  315.         return -1;
  316.     }
  317.     /* Initialize device */
  318.     if(ec_init(if_ec,(unsigned)atoi(argv[5])) != 0){
  319.         free(if_ec->name);
  320.         free((char *)if_ec);
  321.         return -1;
  322.     }
  323.     if_ec->next = ifaces;
  324.     ifaces = if_ec;
  325.     need_disable = 1;        /* must disable ints in malloc */
  326.  
  327.     return 0;
  328. }
  329.